package org.hepeng.fabric.gateway.contract.spring;

import lombok.AllArgsConstructor;
import org.hepeng.fabric.contract.ChainCodeRegistry;
import org.hepeng.fabric.contract.annotation.ContractAPI;
import org.hepeng.fabric.contract.proxy.ContractProxy;
import org.hepeng.fabric.gateway.contract.FabricGatewayHolderContractProvider;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.util.Objects;

/**
 * @author he peng
 * @date 2022/3/25
 */

@EnableConfigurationProperties(ContractProperties.class)
@Configuration
@AllArgsConstructor
public class ContractAutoConfiguration implements InitializingBean {

    private final ContractProperties contractProperties;

    private final DefaultListableBeanFactory beanFactory;

    @Override
    public void afterPropertiesSet() throws Exception {

        FabricGatewayHolderContractProvider contractProvider = new FabricGatewayHolderContractProvider();

        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AnnotationTypeFilter(ContractAPI.class));
        for (String contractPackage : contractProperties.getContractPackages()) {
            for (BeanDefinition component : scanner.findCandidateComponents(contractPackage)) {
                if (Objects.nonNull(component) && StringUtils.hasLength(component.getBeanClassName())) {
                    Class<?> contractAPIClass = ClassUtils.forName(component.getBeanClassName(), Thread.currentThread().getContextClassLoader());
                    ChainCodeRegistry.add(contractAPIClass);

                    Object contract = ContractProxy.newProxy(contractAPIClass, contractProvider);
                    beanFactory.registerSingleton(contractAPIClass.getSimpleName() , contract);
                }
            }
        }
    }
}
